import json
import re
import cv2
from loguru import logger
import requests
import random
import execjs
import time
sess=requests.session()
# https://gt4.geetest.com/
class jiyan4:

    def __init__(self):
        self.proxies={
            "http": "http://127.0.0.1:7890",
            "https": "http://127.0.0.1:7890",
        }
        self.captcha_id = "54088bb07d2df3c46b79f80300b0abbe"

    def generate_random_hex(self):
        return "".join(hex(int(65536 * (1 + random.random())))[3:] for _ in range(4))


    def uuid(self):
        def replacer(c):
            r = random.randint(0, 15)
            v = r if c == 'x' else (r & 0x3 | 0x8)
            return format(v, 'x')

        return ''.join([
            replacer(c) if c in 'xy' else c
            for c in 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
        ])

    """
    获取背景图等..

    """
    def load(self):

        headers = {
            "Accept": "*/*",
            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,ar;q=0.7",
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "Pragma": "no-cache",
            "Referer": "https://gt4.geetest.com/",
            "Sec-Fetch-Dest": "script",
            "Sec-Fetch-Mode": "no-cors",
            "Sec-Fetch-Site": "same-site",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0",
            "sec-ch-ua": "\"Not;A=Brand\";v=\"99\", \"Microsoft Edge\";v=\"139\", \"Chromium\";v=\"139\"",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "\"Windows\""
        }

        url = "https://gcaptcha4.geetest.com/load"
        params = {
            "callback": f"geetest_{str(int(time.time() * 1000))}",
            "captcha_id": self.captcha_id,
            "challenge": self.uuid(),
            "client_type": "web",
            "risk_type": "slide",
            "lang": "zh",
        }
        logger.info(f"load uuid==>{self.uuid()}")
        logger.info(f"load callback==>{params['callback']}")

        response = sess.get(url, headers=headers, params=params,proxies=self.proxies)
        logger.info(f"load status==>{response.status_code}")
        logger.info(f"load text==>{response.text}")
        return response.text

    def parse_and_save(self, response_text):
        # 提取JSON数据
        json_str = re.search(r'geetest_\d+\((.+)\)', response_text).group(1)
        data = json.loads(json_str)

        # 提取关键信息
        lot_number = data['data']['lot_number']
        slice_path = data['data']['slice']

        bg_path = data['data']['bg']
        payload = data['data']['payload']
        process_token = data["data"]["process_token"]

        datetime = data["data"]["pow_detail"]["datetime"]
        version = data["data"]["pow_detail"]["version"]
        bits = data["data"]["pow_detail"]["bits"]
        hashfunc = data["data"]["pow_detail"]["hashfunc"]
        logger.info(f"lot_number: {lot_number}")
        logger.info(f"slice: {slice_path}")
        logger.info(f"bg: {bg_path}")
        logger.info(f"payload: {payload}")
        logger.info(f"process_token: {process_token}")
        logger.info(f"datetime: {datetime}")
        logger.info(f"version: {version}")
        logger.info(f"bits: {bits}")
        logger.info(f"hashfunc: {hashfunc}")

        # 下载图片
        self.download_image(f"https://static.geetest.com/{bg_path}", f"{lot_number}_bg.png")
        self.download_image(f"https://static.geetest.com/{slice_path}", f"{lot_number}_slice.png")

        # 保存JSON
        with open(f"{lot_number}_data.json", 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)

        return lot_number,slice_path,bg_path,payload,process_token,datetime

    def download_image(self, url, filename):
        try:
            response = requests.get(url,proxies=self.proxies)
            if response.status_code == 200:
                with open(filename, 'wb') as f:
                    f.write(response.content)
                logger.info(f"已保存: {filename}")
        except Exception as e:
            logger.info(f"下载失败 {url}: {e}")

    def verify(
            self,
            lot_number,
            payload,
            process_token,
            datetime,
            ):

        dist = self.identify_gap(
            f"{lot_number}_bg.png", f"{lot_number}_slice.png", "out.png"
        )
        logger.info(f"dist==>{dist}")

        # 读取简化后的JavaScript代码
        with open("main.js", "r", encoding="utf-8") as f:
            jsCode = f.read()
        js_com = execjs.compile(jsCode)

        # 直接调用generateW函数，一步得到最终的w值
        w = js_com.call(
            "generateW",
            dist,  # 距离
            datetime,  # 时间
            self.captcha_id,  # captcha_id
            lot_number,  # lot_number
        )

        logger.info(f"w==>{w}")

        # 后续的verify请求代码保持不变
        headers = {
            "Accept": "*/*",
            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,ar;q=0.7",
            "Cache-Control": "no-cache",
            "Connection": "keep-alive",
            "Pragma": "no-cache",
            "Referer": "https://gt4.geetest.com/",
            "Sec-Fetch-Dest": "script",
            "Sec-Fetch-Mode": "no-cors",
            "Sec-Fetch-Site": "same-site",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0",
            "sec-ch-ua": "\"Not;A=Brand\";v=\"99\", \"Microsoft Edge\";v=\"139\", \"Chromium\";v=\"139\"",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "\"Windows\""
        }

        url = "https://gcaptcha4.geetest.com/verify"
        params = {
            "callback": f"geetest_{str(int(time.time() * 1000))}",
            "captcha_id": self.captcha_id,
            "client_type": "web",
            "lot_number": lot_number,
            "risk_type": "slide",
            "payload": payload,
            "process_token": process_token,
            "payload_protocol": "1",
            "pt": "1",
            "w": w
        }
        logger.info(f"verify callback==>{params['callback']}")
        response = sess.get(url, headers=headers,params=params, proxies=self.proxies)
        logger.info(f"verify status===>{response.status_code}")
        logger.info(f"verify text==>{response.text}")
        return response.text

    def identify_gap(self,bg, tp, out):
        """
        bg: 背景图片
        tp: 缺口图片
        out:输出图片
        """
        # 读取背景图片和缺口图片
        bg_img = cv2.imread(bg)  # 背景图片
        tp_img = cv2.imread(tp)  # 缺口图片

        # 识别图片边缘
        bg_edge = cv2.Canny(bg_img, 100, 200)
        tp_edge = cv2.Canny(tp_img, 100, 200)

        # 转换图片格式
        bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
        tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)

        # 缺口匹配
        res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)  # 寻找最优匹配

        # 绘制方框
        th, tw = tp_pic.shape[:2]
        tl = max_loc  # 左上角点的坐标
        br = (tl[0] + tw, tl[1] + th)  # 右下角点的坐标
        cv2.rectangle(bg_img, tl, br, (0, 0, 255), 2)  # 绘制矩形
        cv2.imwrite(out, bg_img)  # 保存在本地

        # 返回缺口的X坐标
        return tl[0]


if __name__ == '__main__':
    gt = jiyan4()
    text=gt.load()
    lot_number, slice_path, bg_path, payload, process_token, datetime=gt.parse_and_save(text)
    gt.verify(
        lot_number, payload, process_token, datetime
    )
